/*
 * CDiskSpaceMonitor.cpp
 *
 *  Created on: 2017年2月4日
 *      Author: zhengboyuan
 */

#include "CDiskSpaceMonitor.h"
#include <stdio.h>
#include "CLog.h"


CDiskSpaceMonitor::CDiskSpaceMonitor():
	m_listener()
{
}

CDiskSpaceMonitor::~CDiskSpaceMonitor()
{
	close();
}

void CDiskSpaceMonitor::setListener(DiskSpaceMonitorListener* listener)
{
	m_listener = listener;
}

int CDiskSpaceMonitor::open()
{
	start();

	return 0;
}

void CDiskSpaceMonitor::close()
{
	if (isRunning())
	{
		stop();
	}
}

bool CDiskSpaceMonitor::isOpen()
{
	return isRunning();
}

bool CDiskSpaceMonitor::add(const std::string& dirpath, int64_t freeSpace)
{
	CLog::debug("CDiskSpaceMonitor::add. dir:%s, freeSpace:%d\n", dirpath.c_str(), (int)(freeSpace/1024/1024));
	
	DiskSpace diskspace;
	if (!getDiskSpace(dirpath, diskspace))
	{
		return false;
	}

	diskspace.dirpath = dirpath;

	diskspace.minPercent = 0;
	diskspace.minFreeSpace = freeSpace;

	add(diskspace);

	return true;
}

bool CDiskSpaceMonitor::add(const std::string& dirpath, double freePercent)
{
	CLog::debug("CDiskSpaceMonitor::add. dir:%s, freePercent:%f\n", dirpath.c_str(), freePercent);
	
	DiskSpace diskspace;
	if (!getDiskSpace(dirpath, diskspace))
	{
		CLog::warning("failed to get disk space. %s\n", dirpath.c_str());
		return false;
	}

	diskspace.dirpath = dirpath;

	diskspace.minPercent = freePercent;
	diskspace.minFreeSpace = (int64_t)(freePercent * diskspace.totalSpace);

	add(diskspace);

	return true;
}

void CDiskSpaceMonitor::clear()
{
	comn::AutoCritSec lock(m_cs);
	m_disks.clear();
}

bool CDiskSpaceMonitor::getDiskSpace(const std::string& dirpath, DiskSpace& diskspace)
{
	bool found = DiskSpaceMonitor::getDiskSpace(dirpath, diskspace.totalSpace, diskspace.freeSpace);
	if (found)
	{
		if (diskspace.totalSpace > 0)
		{
			diskspace.percent = diskspace.freeSpace / (double)diskspace.totalSpace;
		}
	}
	return found;
}

void CDiskSpaceMonitor::poll()
{
	//CLog::debug("CDiskSpaceMonitor::poll. count:%d\n", m_disks.size());
	
	size_t idx = 0;
	while (idx < m_disks.size())
	{
		DiskSpace diskspace;
		if (check(idx, diskspace))
		{
			fireCheck(diskspace);
		}

		idx ++;
	}
}

void CDiskSpaceMonitor::add(const DiskSpace& diskspace)
{
	comn::AutoCritSec lock(m_cs);

	size_t idx = find(diskspace.dirpath);
	if (idx != -1)
	{
		m_disks[idx] = diskspace;
	}
	else
	{
		m_disks.push_back(diskspace);
	}
}

size_t CDiskSpaceMonitor::find(const std::string& dirpath)
{
	for (size_t i = 0; i < m_disks.size(); ++ i)
	{
		if (m_disks[i].dirpath == dirpath)
		{
			return i;
		}
	}
	return -1;
}

bool CDiskSpaceMonitor::check(size_t idx, DiskSpace& diskspace)
{
	comn::AutoCritSec lock(m_cs);
	if (idx >= m_disks.size())
	{
		return false;
	}

	diskspace = m_disks[idx];

	if (!getDiskSpace(diskspace.dirpath, diskspace))
	{
		return false;
	}

	//int freeSpace = (int)(diskspace.freeSpace / 1024 / 1024);
	//int minSpace = (int)(diskspace.minFreeSpace / 1024 / 1024);
	//printf("free:%d, min:%d\n", freeSpace, minSpace);

	return (diskspace.freeSpace <= diskspace.minFreeSpace);
}

void CDiskSpaceMonitor::fireCheck(const DiskSpace& diskspace)
{
	if (m_listener)
	{
		m_listener->onNotEnoughSpace(diskspace.dirpath, diskspace.totalSpace, diskspace.freeSpace, diskspace.percent);
	}
}

int CDiskSpaceMonitor::run()
{
	while (!m_canExit)
	{
		int ms = DISKSPACE_POLL_INTERVAL * 1000;
		m_event.timedwait(ms);

		if (m_canExit)
		{
			break;
		}
		
		poll();
	}
	
	return 0;
}

void CDiskSpaceMonitor::doStop()
{
	m_event.post();
}